#include "StdAfx.h"
#include "offlinecaptor.h"


ACE_Thread_Mutex offlinecaptor::_mutex;
offlinecaptor* offlinecaptor::_instance=0;
offlinecaptor::offlinecaptor(void):_Log(0),_ringfifo(0)
{
	ACE_OS::memset(this->_device, 0x00, sizeof(this->_device));
}


offlinecaptor::~offlinecaptor(void)
{
	nids_exit();
}
offlinecaptor* offlinecaptor::get_instance(){
	if(_instance==0){
		_mutex.acquire();
		if(_instance==0){
			_instance=new offlinecaptor;
			_mutex.release();
			return _instance;
		}
		_mutex.release();
	}
	return _instance;
}
void offlinecaptor::destroy_instance(){
	_mutex.acquire();
	if(_instance){
		delete _instance;
		_instance=0;
	}
	_mutex.release();
}

void offline_tcp_callback(struct tcp_stream *tcp_http_connection, void **param){
	offlinecaptor* ins=offlinecaptor::get_instance();
	if(ins==0){
		return ;
	}
	int ret=0;
	struct tuple4 ip_and_port = tcp_http_connection->addr;
	tcp_connection_info tci;
	memset(&tci,0,sizeof(tcp_connection_info));
	tci.saddr=ip_and_port.saddr;
	tci.daddr=ip_and_port.daddr;
	tci.source=ip_and_port.source;
	tci.dest=ip_and_port.dest;
	if (tcp_http_connection->nids_state == NIDS_JUST_EST)
	{
		//if (tcp_http_connection->addr.dest != 80)
		//{
		//	return ;
		//}
		tcp_http_connection->client.collect++; 
		tcp_http_connection->server.collect++; 

		tci.state=tcp_conn_just_est;
		ins->put_data_into_fifo(tci);
		return ;
	}
	if (tcp_http_connection->nids_state == NIDS_CLOSE)
	{

		tci.state=tcp_conn_close;
		ins->put_data_into_fifo(tci);
		return ;
	}
	if (tcp_http_connection->nids_state == NIDS_RESET)
	{

		tci.state=tcp_conn_rst;
		ins->put_data_into_fifo(tci);
		return ;
	}
	if (tcp_http_connection->nids_state == NIDS_DATA)
	{

		if(tcp_http_connection->client.count_new){
			struct half_stream *hlf;
			hlf=&tcp_http_connection->client;
			tci.state=tcp_conn_data;
			tci.direct=fromserver;
			memcpy(tci.data,hlf->data,std::min(hlf->count_new,1500-1));
			tci.datalen=std::min(hlf->count_new,1500-1);
			ins->put_data_into_fifo(tci);
		}
		if(tcp_http_connection->server.count_new){
			struct half_stream *hlf;
			hlf=&tcp_http_connection->server;
			tci.state=tcp_conn_data;
			tci.direct=fromclient;
			memcpy(tci.data,hlf->data,std::min(hlf->count_new,1500-1));
			tci.datalen=std::min(hlf->count_new,1500-1);
			ins->put_data_into_fifo(tci);
		}

	}
}
int offlinecaptor::init(){

	//if(!nids_init()){
	//	if(_Log){
	//		_Log->error("captor: nids_init failed. \n");
	//	}	
	//	else{
	//		printf("captor: nids_init failed.\n");
	//	}
	//	_errmsg="nids_init failed please change network interface.";
	//	return -1;
	//}
	nids_init_dump();
	nids_register_tcp((void *)(::offline_tcp_callback));
	return 0;
}

int offlinecaptor::load_config(const char * _config_filename){
	ACE_TString str;
	ACE_Configuration_Heap config;
	if (config.open() == -1)
	{
		ACE_ERROR_RETURN((LM_ERROR, ACE_TEXT("(%P|%t) %p\n"), ACE_TEXT("config.open()")), -1);
	}

	ACE_Ini_ImpExp config_importer(config);
	if (config_importer.import_config(ACE_TEXT(_config_filename)) == -1)
	{
		ACE_ERROR_RETURN((LM_ERROR, ACE_TEXT("(%P|%t) %p\n"), _config_filename), -1);
	}

	ACE_Configuration_Section_Key status_section;
	if (config.open_section (config.root_section(), ACE_TEXT(CAP_CONF_SECTION), 0, status_section) == -1)
	{
		ACE_ERROR_RETURN ((LM_ERROR, ACE_TEXT("(%P|%t) %p\n"), ACE_TEXT ("Can't open [PCAPCONF] section")), -1);
	}

	if (config.get_string_value(status_section, ACE_TEXT(CAP_CONF_DEVICE), str) != -1)
	{
		if (ACE_OS::strcmp(str.c_str(), _device) != 0)
		{
			//ACE_DEBUG((LM_DEBUG, ACE_TEXT("(%P|%t) [%s]->'%s' is updated (%s)->(%s)/n"), HTTP_LOG_CONF_SECTION, HTTP_LOG_CONF_OUTDIR, this->parentdir_, str.c_str()));
			ACE_OS::memset(this->_device, 0x00, sizeof(this->_device));
			ACE_OS::strncpy(this->_device, str.c_str(), sizeof(this->_device));
		}
		str.clear();
	}
	return 0;
}
int offlinecaptor::svc(){
	if(_Log){
		_Log->message("offcaptor: task begin...\n");
	}
	while(1){
		nids_init_dump();
		nids_register_tcp((void *)(::offline_tcp_callback));
		nids_open_dump((char*)this->_offline_file.c_str());
		break;
	}
	if(_Log){
		_Log->message("offcaptor: task done.\n");
	}
	return 0;
}
void offlinecaptor::put_data_into_fifo(tcp_connection_info& tci){
	int ret=0;

	if(_ringfifo){
		ret=_ringfifo->push_back(tci);
		if(ret<0){
			if(_Log){
				_Log->error("offcaptor: ringfifo push_back failed. \n");
			}	
		}
		else if(ret==1){
			if(_Log){
				_Log->error("offcaptor: ringfifo disabled. \n");
			}	
		}
		else if(ret==2){
			if(_Log){
				_Log->error("offcaptor: ringfifo push_back time out. \n");
			}
		}
	}
}